/***************************************************
*
* cismet GmbH, Saarbruecken, Germany
*
* ... and it just works.
*
****************************************************/
package de.cismet.cismap.commons.gui.layerwidget;
import edu.umd.cs.piccolo.PNode;
import org.openide.util.Lookup;
import org.openide.util.Lookup.Result;
import org.openide.util.NbBundle;
import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.AbstractCellEditor;
import javax.swing.DefaultCellEditor;
import javax.swing.DefaultComboBoxModel;
import javax.swing.DefaultListCellRenderer;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JProgressBar;
import javax.swing.JSlider;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.JTree;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;
import javax.swing.tree.TreeCellEditor;
import de.cismet.cismap.commons.Debug;
import de.cismet.cismap.commons.LayerInfoProvider;
import de.cismet.cismap.commons.ModeLayer;
import de.cismet.cismap.commons.RetrievalServiceLayer;
import de.cismet.cismap.commons.featureservice.AbstractFeatureService;
import de.cismet.cismap.commons.featureservice.QueryEditorDialog;
import de.cismet.cismap.commons.featureservice.WebFeatureService;
import de.cismet.cismap.commons.featureservice.factory.AbstractFeatureFactory;
import de.cismet.cismap.commons.featureservice.factory.FeatureFactory;
import de.cismet.cismap.commons.featureservice.style.BasicStyle;
import de.cismet.cismap.commons.featureservice.style.StyleDialogInterface;
import de.cismet.cismap.commons.featureservice.style.StyleDialogStarter;
import de.cismet.cismap.commons.interaction.CismapBroker;
import de.cismet.cismap.commons.interaction.events.ActiveLayerEvent;
import de.cismet.cismap.commons.raster.wms.AbstractWMS;
import de.cismet.cismap.commons.raster.wms.WMSLayer;
import de.cismet.cismap.commons.raster.wms.WMSServiceLayer;
import de.cismet.cismap.commons.util.SLDStyleUtil;
import de.cismet.cismap.commons.wms.capabilities.Style;
import de.cismet.tools.CismetThreadPool;
import de.cismet.tools.gui.StaticSwingTools;
/**
* DOCUMENT ME!
*
* @author thorsten.hell@cismet.de
* @version $Revision$, $Date$
*/
public class ActiveLayerTableCellEditor extends AbstractCellEditor implements TableCellEditor,
TreeCellEditor,
PropertyChangeListener {
//~ Static fields/initializers ---------------------------------------------
protected static final boolean DEBUG = Debug.DEBUG;
//~ Instance fields --------------------------------------------------------
private final org.apache.log4j.Logger logger = org.apache.log4j.Logger.getLogger(this.getClass());
private JCheckBox informationBox;
private Object value;
private JTable table;
private JComboBox cbbStyleChooser;
private StyleDialogInterface styleDialog; // = new StyleDialog(new JFrame("XXX"),
// true);
private JButton moreButton = new JButton(". ."); // NOI18N
private javax.swing.ImageIcon unselectedStyleIcon = new javax.swing.ImageIcon(getClass().getResource(
"/de/cismet/cismap/commons/raster/wms/res/disabledStyle.png")); // NOI18N
private JButton wfsStyleButton = new JButton() {
// paints the rectangle inside the button that creates the StyleDialog
@Override
protected void paintComponent(final Graphics g) {
de.cismet.cismap.commons.featureservice.style.Style style = null;
final AbstractFeatureService service = (AbstractFeatureService)value;
final FeatureFactory ff = service.getFeatureFactory();
BasicStyle basicStyle = null;
if (ff instanceof AbstractFeatureFactory) {
final AbstractFeatureFactory aff = (AbstractFeatureFactory)ff;
final List<org.deegree.style.se.unevaluated.Style> styleList = aff.getStyle(aff.layerName);
basicStyle = SLDStyleUtil.getBasicStyleFromSLDStyle(styleList);
}
if (basicStyle != null) {
style = basicStyle;
} else {
if (((AbstractFeatureService)value).getLayerProperties() != null) {
style = ((AbstractFeatureService)value).getLayerProperties().getStyle();
}
}
try {
final Graphics2D g2d = (Graphics2D)g;
if (style.isDrawFill() && (style.getFillColor() != null)) {
g2d.setColor((Color)style.getFillColor());
g2d.fillRect(10, 4, getWidth() - 20, getHeight() - 8);
}
if (style.isDrawLine() && (style.getLineColor() != null)) {
g2d.setColor((Color)style.getLineColor());
final float width = new Float(Math.min(3.0f, style.getLineWidth())).intValue();
g2d.setStroke(new BasicStroke(width));
g2d.drawRect(10, 4, getWidth() - 20, getHeight() - 8);
}
} catch (Exception ex) {
}
}
};
private JLabel customStyleLab = new JLabel();
private DefaultCellEditor informationCellEditor;
private DefaultCellEditor stylesCellEditor;
private JProgressBar progress = new JProgressBar(0, 100);
private JSlider slider = new JSlider(0, 100);
private JLabel visibilityLabel = new JLabel("", JLabel.CENTER); // NOI18N
private JLabel emptyLabel = new JLabel();
private RetrievalServiceLayer wmsServiceLayerThatFiresPropertyChangeEvents = null;
//~ Constructors -----------------------------------------------------------
/**
* Creates a new instance of ActiveLayerTableCellEditor.
*/
public ActiveLayerTableCellEditor() {
// progress.setUI(new MetalProgressBarUI());
progress.setString(""); // NOI18N
progress.setStringPainted(true);
progress.setLayout(
new BorderLayout(2, 2));
visibilityLabel.setOpaque(false);
visibilityLabel.addMouseListener(new MouseAdapter() {
// deactivate & hide layer on doubleclick or
// if already hidden activate, show and do a new retrieve
@Override
public void mouseClicked(final MouseEvent e) {
if (e.getClickCount() == 2) {
if (value instanceof RetrievalServiceLayer) {
final RetrievalServiceLayer layer = ((RetrievalServiceLayer)value);
final boolean flag = layer.getPNode().getVisible();
layer.setEnabled(!flag);
// fireTreeNodesChanged(this, new Object[]{root}, null, null);
if (!flag) {
// layer.setRefreshNeeded(true);
layer.retrieve(true);
}
if (layer instanceof AbstractFeatureService) {
((AbstractFeatureService)layer).setVisible(!flag);
} else if (layer instanceof AbstractWMS) {
((AbstractWMS)layer).setVisible(!flag);
} else if (layer instanceof ModeLayer) {
((ModeLayer)layer).setVisible(!flag);
}
layer.getPNode().setVisible(!flag);
final ActiveLayerEvent ale = new ActiveLayerEvent();
ale.setLayer(value);
CismapBroker.getInstance().fireLayerVisibilityChanged(ale);
table.repaint();
}
}
}
});
informationBox = new JCheckBox();
informationBox.setHorizontalAlignment(JCheckBox.CENTER);
informationCellEditor = new DefaultCellEditor(informationBox);
cbbStyleChooser = new JComboBox();
stylesCellEditor = new DefaultCellEditor(cbbStyleChooser);
cbbStyleChooser.setEditable(false);
cbbStyleChooser.setRenderer(new StyleChooserCellRenderer());
informationBox.addActionListener(new ActionListener() {
@Override
public void actionPerformed(final ActionEvent e) {
try {
if (value instanceof LayerInfoProvider) {
((LayerInfoProvider)value).setLayerQuerySelected(informationBox.isSelected());
final ActiveLayerEvent ale = new ActiveLayerEvent();
ale.setLayer(value);
CismapBroker.getInstance().fireLayerInformationStatusChanged(ale);
}
// WMSLayer l = null;
// if (value instanceof WMSLayer) {
// l = ((WMSLayer) value);
// } else if (value instanceof WMSServiceLayer && ((WMSServiceLayer) value).getWMSLayers().size() == 1) {
// l = ((WMSLayer) ((WMSServiceLayer) value).getWMSLayers().get(0));
// }
// l.setQuerySelected(informationBox.isSelected());
// A workaround for a ugly bug which denies the refresh of a cell
// in a treetable when it is in editing mode
table.getColumnModel().getColumn(3).getCellEditor().stopCellEditing();
} catch (Exception ex) {
logger.error("Error in actionPerformed of the informationCheckBos", ex);
}
}
});
cbbStyleChooser.addActionListener(new ActionListener() {
@Override
public void actionPerformed(final ActionEvent e) {
try {
WMSLayer l = null;
if (value instanceof WMSLayer) {
l = ((WMSLayer)value);
} else if ((value instanceof WMSServiceLayer)
&& (((WMSServiceLayer)value).getWMSLayers().size() == 1)) {
l = ((WMSLayer)((WMSServiceLayer)value).getWMSLayers().get(0));
}
if ((l != null) && !(l.getSelectedStyle().equals((Style)cbbStyleChooser.getSelectedItem()))) {
final ActiveLayerEvent ale = new ActiveLayerEvent();
ale.setLayer(l.getParentServiceLayer());
CismapBroker.getInstance().fireLayerRemoved(ale);
l.setSelectedStyle((Style)cbbStyleChooser.getSelectedItem());
((de.cismet.cismap.commons.retrieval.RetrievalService)value).retrieve(true);
CismapBroker.getInstance().fireLayerAdded(ale);
}
l.setSelectedStyle((Style)cbbStyleChooser.getSelectedItem());
final ActiveLayerEvent ale = new ActiveLayerEvent();
ale.setLayer(l.getParentServiceLayer());
((de.cismet.cismap.commons.retrieval.RetrievalService)value).retrieve(true);
// ((RetrievalService)value).retrieve();
CismapBroker.getInstance().fireLayerRemoved(ale);
CismapBroker.getInstance().fireLayerAdded(ale);
} catch (Exception ex) {
logger.error("Error while changing the style", ex); // NOI18N
}
}
});
moreButton.setFocusPainted(false);
moreButton.setEnabled(false);
moreButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(final ActionEvent e) {
if (DEBUG) {
if (logger.isDebugEnabled()) {
logger.debug("invoke FeatureService-QueryEditorDialog"); // NOI18N
}
}
final QueryEditorDialog dia = new QueryEditorDialog(
StaticSwingTools.getParentFrame(moreButton),
true,
((WebFeatureService)value).getQuery());
StaticSwingTools.showDialog(dia);
if (dia.getReturnStatus() == QueryEditorDialog.RET_OK) {
((WebFeatureService)value).setQuery(dia.getQueryString());
}
}
});
customStyleLab.addMouseListener(new StyleMouseListener());
wfsStyleButton.setFocusPainted(false);
wfsStyleButton.setEnabled(true);
wfsStyleButton.setBorderPainted(false);
wfsStyleButton.setContentAreaFilled(false);
wfsStyleButton.addMouseListener(new StyleMouseListener());
progress.add(slider, BorderLayout.CENTER);
slider.setOpaque(false);
slider.setValueIsAdjusting(true);
slider.addChangeListener(
new ChangeListener() {
@Override
public void stateChanged(final ChangeEvent e) {
final JSlider slider = (JSlider)e.getSource();
if (value instanceof RetrievalServiceLayer) {
final float f = (float)(slider.getValue() * 0.01);
((RetrievalServiceLayer)value).setTranslucency(f);
final PNode pi = ((RetrievalServiceLayer)value).getPNode();
if (pi != null) {
pi.setTransparency(f);
pi.repaint();
}
if (!slider.getValueIsAdjusting()) {
((RetrievalServiceLayer)value).setTranslucency(f);
}
}
}
});
// _WTF? ....................................................................
slider.addMouseListener(
new MouseAdapter() {
@Override
public void mouseClicked(final MouseEvent e) {
if (DEBUG) {
if (logger.isDebugEnabled()) {
logger.debug("Click" + e); // NOI18N
}
}
}
@Override
public void mouseReleased(final MouseEvent e) {
// übergibt die Darstellung wieder an den Renderer
ActiveLayerTableCellEditor.this.stopCellEditing();
}
});
slider.dispatchEvent(
new MouseEvent(
slider,
MouseEvent.MOUSE_CLICKED,
System.currentTimeMillis(),
MouseEvent.BUTTON1_MASK,
3,
2,
1,
false,
MouseEvent.BUTTON1));
// _WTF? ....................................................................
}
//~ Methods ----------------------------------------------------------------
/**
* Sets an initial <I>value</I> for the editor. This will cause the editor to stopEditing and lose any partially
* edited value if the editor is editing when this method is called.
*
* <p>Returns the component that should be added to the client's Component hierarchy. Once installed in the client's
* hierarchy this component will then be able to draw and receive user input.</p>
*
* @param tree the JTree that is asking the editor to edit; this parameter can be null
* @param value the value of the cell to be edited
* @param isSelected true is the cell is to be renderer with selection highlighting
* @param expanded true if the node is expanded
* @param leaf true if the node is a leaf node
* @param row the row index of the node being edited
*
* @return the component for editing
*/
@Override
public Component getTreeCellEditorComponent(final JTree tree,
final Object value,
final boolean isSelected,
final boolean expanded,
final boolean leaf,
final int row) {
if (DEBUG) {
if (logger.isDebugEnabled()) {
logger.debug("TreeCellEditor requested"); // NOI18N
}
}
final JTextField treeEditorTextField = new JTextField();
treeEditorTextField.setEditable(true);
final DefaultCellEditor treeEditor = new DefaultCellEditor(treeEditorTextField);
return treeEditor.getTreeCellEditorComponent(tree, value, isSelected, expanded, leaf, row);
}
/**
* Sets an initial <code>value</code> for the editor. This will cause the editor to <code>stopEditing</code> and
* lose any partially edited value if the editor is editing when this method is called.
*
* <p>Returns the component that should be added to the client's <code>Component</code> hierarchy. Once installed in
* the client's hierarchy this component will then be able to draw and receive user input.</p>
*
* @param table the <code>JTable</code> that is asking the editor to edit; can be <code>null</code>
* @param value the value of the cell to be edited; it is up to the specific editor to interpret and draw
* the value. For example, if value is the string "true", it could be rendered as a string or
* it could be rendered as a check box that is checked. <code>null</code> is a valid value
* @param isSelected true if the cell is to be rendered with highlighting
* @param row the row of the cell being edited
* @param column the column of the cell being edited
*
* @return the component for editing
*/
@Override
public Component getTableCellEditorComponent(
final JTable table,
final Object value,
final boolean isSelected,
final int row,
final int column) {
final int realColumn = table.convertColumnIndexToModel(column);
this.value = value;
this.table = table;
WMSLayer wmsLayer = null;
LayerInfoProvider layer = null;
if (value instanceof ModeLayer) {
return getTableCellEditorComponent(table, ((ModeLayer)value).getCurrentLayer(), isSelected, row, column);
}
if (value instanceof WMSLayer) {
wmsLayer = ((WMSLayer)value);
} else if (value instanceof WMSServiceLayer) {
wmsLayer = (WMSLayer)((WMSServiceLayer)value).getWMSLayers().get(0);
}
if (value instanceof LayerInfoProvider) {
layer = (LayerInfoProvider)value;
}
if (realColumn == 0) {
final TableCellRenderer renderer = table.getCellRenderer(row, column);
visibilityLabel.setIcon(
((JLabel)renderer.getTableCellRendererComponent(table, value, isSelected, isSelected, row, column))
.getIcon());
return visibilityLabel;
} else if (realColumn == 2) {
if (DEBUG) {
if (logger.isDebugEnabled()) {
logger.debug("Editor column=" + realColumn); // NOI18N
}
}
if (value instanceof WMSServiceLayer) {
try {
if (DEBUG) {
if (logger.isDebugEnabled()) {
logger.debug("Combo"); // NOI18N
}
}
final DefaultComboBoxModel model = new DefaultComboBoxModel(wmsLayer.getOgcCapabilitiesLayer()
.getStyles());
cbbStyleChooser.setModel(model);
cbbStyleChooser.setSelectedItem(wmsLayer.getSelectedStyle());
return stylesCellEditor.getTableCellEditorComponent(
table,
wmsLayer.getSelectedStyle(),
isSelected,
row,
column);
} catch (Exception e) {
logger.warn("Error while setting the StyleEditor", e); // NOI18N
return null;
}
} else {
if (DEBUG) {
if (logger.isDebugEnabled()) {
logger.debug("StyleButton"); // NOI18N
}
}
final AbstractFeatureService service = (AbstractFeatureService)value;
if ((service.getLayerProperties() != null)
&& (service.getLayerProperties().getAttributeTableRuleSet() != null)
&& (service.getLayerProperties().getAttributeTableRuleSet().getFeatureClass() != null)) {
customStyleLab.setHorizontalAlignment(JLabel.LEFT);
customStyleLab.setText(NbBundle.getMessage(
ActiveLayerTableCellRenderer.class,
"ActiveLayerTableCellRenderer.getTableCellRendererComponent().customStyle"));
customStyleLab.setIcon(unselectedStyleIcon);
return customStyleLab;
}
return wfsStyleButton;
}
} else if (realColumn == 3) {
return informationCellEditor.getTableCellEditorComponent(
table,
layer.isLayerQuerySelected(),
isSelected,
row,
column);
} else if (realColumn == 4) {
if (wmsServiceLayerThatFiresPropertyChangeEvents != null) {
wmsServiceLayerThatFiresPropertyChangeEvents.removePropertyChangeListener(this);
}
((RetrievalServiceLayer)value).addPropertyChangeListener(this);
wmsServiceLayerThatFiresPropertyChangeEvents = ((RetrievalServiceLayer)value);
slider.setValue((int)(((RetrievalServiceLayer)value).getTranslucency() * 100));
slider.requestFocus();
if (((RetrievalServiceLayer)value).getProgress() == -1) {
progress.setIndeterminate(true);
} else {
progress.setIndeterminate(false);
}
progress.setValue(((RetrievalServiceLayer)value).getProgress());
slider.updateUI();
return progress;
} else if (realColumn == 5) {
if (value instanceof WMSServiceLayer) {
moreButton.setEnabled(false);
} else if (value instanceof WebFeatureService) {
moreButton.setEnabled(true);
}
return moreButton;
} else {
return null;
}
}
/**
* Returns the value contained in the editor.
*
* @return the value contained in the editor
*/
@Override
public Object getCellEditorValue() {
return value;
}
/**
* This method gets called when a bound property is changed.
*
* @param evt A PropertyChangeEvent object describing the event source and the property that has changed.
*/
@Override
public void propertyChange(final PropertyChangeEvent evt) {
if (DEBUG) {
if (logger.isDebugEnabled()) {
logger.debug("Progressvalue in Editor changed"); // NOI18N
}
}
if ((evt.getSource() instanceof RetrievalServiceLayer) && evt.getPropertyName().equals("progress")) // NOI18N
{
final int newValue = ((Integer)(evt.getNewValue())).intValue();
if (newValue == 0) {
progress.setIndeterminate(true);
} else {
progress.setIndeterminate(false);
progress.setValue(newValue);
}
}
}
/**
* Calls <code>fireEditingCanceled</code>.
*/
@Override
public void cancelCellEditing() {
if (wmsServiceLayerThatFiresPropertyChangeEvents != null) {
wmsServiceLayerThatFiresPropertyChangeEvents.removePropertyChangeListener(this);
}
super.cancelCellEditing();
}
/**
* Calls <code>fireEditingStopped</code> and returns true.
*
* @return true
*/
@Override
public boolean stopCellEditing() {
if (wmsServiceLayerThatFiresPropertyChangeEvents != null) {
wmsServiceLayerThatFiresPropertyChangeEvents.removePropertyChangeListener(this);
}
final boolean retValue;
try {
retValue = super.stopCellEditing();
} finally {
}
return retValue;
}
//~ Inner Classes ----------------------------------------------------------
/**
* DOCUMENT ME!
*
* @version $Revision$, $Date$
*/
private class StyleMouseListener extends MouseAdapter {
//~ Methods ------------------------------------------------------------
// creates and shows the StyleDialog on doubleclick
@Override
public void mouseClicked(final MouseEvent e) {
// Event Dispatch Thread TERROR:
// FIXME: ACHTUNG alle Exceptions die in dieser Operation auftreten und
// nicht explizit gefangen werden, werden nicht auf der Console ausgegeben?!
if (e.getClickCount() == 2) {
final AbstractFeatureService selectedService = (AbstractFeatureService)value;
/*
* final JumpSLDEditor editor = new JumpSLDEditor();
*
* editor.ConfigureEditor( selectedService, StaticSwingTools.getParentFrame(wfsStyleButton),
* CismapBroker.getInstance().getMappingComponent());
*/
final Frame parentFrame = StaticSwingTools.getParentFrame(wfsStyleButton);
final ArrayList<String> args = new ArrayList<String>();
args.add("Allgemein");
args.add("Darstellung");
args.add("Massstab");
args.add("Thematische Farbgebung");
args.add("Beschriftung");
args.add("TextEditor");
// args.add("Begleitsymbole");
final StyleDialogStarter starter = new StyleDialogStarter(
parentFrame,
selectedService,
args,
500);
starter.start();
}
}
}
}
/**
* DOCUMENT ME!
*
* @version $Revision$, $Date$
*/
class StyleChooserCellRenderer extends DefaultListCellRenderer {
//~ Instance fields --------------------------------------------------------
private ImageIcon styleIcon;
//~ Constructors -----------------------------------------------------------
/**
* Creates a new StyleChooserCellRenderer object.
*/
public StyleChooserCellRenderer() {
styleIcon = new ImageIcon(getClass().getResource("/de/cismet/cismap/commons/raster/wms/res/style.png")); // NOI18N
}
//~ Methods ----------------------------------------------------------------
@Override
public Component getListCellRendererComponent(final JList list,
final Object listValue,
final int index,
final boolean isSelected,
final boolean cellHasFocus) {
final JLabel retValue;
retValue = (JLabel)super.getListCellRendererComponent(list, listValue, index, isSelected, cellHasFocus);
retValue.setText(((Style)listValue).getTitle());
retValue.setIcon(styleIcon);
retValue.setIconTextGap(4);
return retValue;
}
}